package com.huiying.controller;

import com.huiying.context.BaseContext;
import com.huiying.entity.entity.Conversation;
import com.huiying.entity.entity.Message;
import com.huiying.entity.entity.User;
import com.huiying.entity.result.Result;
import com.huiying.entity.vo.UserVO;
import com.huiying.service.ConversationService;
import com.huiying.service.MessageService;
import com.huiying.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.security.Principal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

/**
 * @Author: lsh
 * @Date: 2024/12/14/21:19
 * @Description: 消息相关接口
 */
//@Controller
@RestController
@Api(tags = "消息相关接口") // 如果你的Swagger依赖是springfox，这个注解是正确的
@Slf4j // Lombok 日志注解
public class ChatController {

    @Autowired
    private SimpMessagingTemplate messagingTemplate; // 用于发送消息给特定用户

    @Autowired
    private MessageService messageService;
    @Autowired
    private ConversationService conversationService;
    @Autowired
    private UserService userService;

    /**
     * 处理客户端发送的聊天消息
     * 客户端发送到 /app/chat.sendMessage
     *
     * @param message 客户端发送的消息体，应包含 content, receiverId, type 等
     * @param principal 当前认证用户的 Principal 对象，由 Spring WebSocket 框架注入
     * 在 WebSocketConfig 中设置的 UsernamePasswordAuthenticationToken 会被注入到这里
     */
    @MessageMapping("/chat.sendMessage")
    @ApiOperation("发送聊天消息") // 为Swagger添加操作说明
    public void sendMessage(@Payload Message message, Principal principal) {
        // 从 Principal 对象获取发送者ID
        // principal.getName() 返回的是您在 WebSocketConfig 中设置的 userId.toString()
        if (principal == null || principal.getName() == null) {
            log.warn("未认证用户（Principal中无ID）尝试发送消息！");
            // 理论上这里不应该被触发，因为未认证的用户在 WebSocketConfig 中就已被拒绝连接
            return;
        }
        Long senderId = Long.valueOf(principal.getName());

        //根据 senderId 从数据库查询发送者信息
        UserVO sender = userService.getById(senderId); // 假设 userService 有 getById 方法
        if (sender == null) {
            log.error("找不到ID为 {} 的发送者用户", senderId);
            return;
        }


        Long receiverId = message.getReceiverId(); // 接收者ID

        if (receiverId == null) {
            log.warn("消息接收者ID为空，发送失败。SenderId: {}", senderId);
            return;
        }

        // 1. 查找或创建会话
        Long user1Id = Math.min(senderId, receiverId);
        Long user2Id = Math.max(senderId, receiverId);

        Conversation conversation = conversationService.findOrCreateConversation(user1Id, user2Id);
        if (conversation == null) {
            log.error("无法创建或找到会话。User1Id: {}, User2Id: {}", user1Id, user2Id);
            return;
        }

        // 2. 设置消息属性
        message.setSenderId(senderId);
        message.setReceiverId(receiverId);
        message.setConversationId(conversation.getId());
        message.setCreatedTime(LocalDateTime.now());
        message.setStatus(Message.MessageStatus.SENT);

        if (message.getType() == null) {
            message.setType(Message.MessageType.TEXT);
        }

        // 3. 将查询到的发送者信息设置到 message 对象中
        message.setSenderUsername(sender.getUsername());
        message.setSenderAvatar(sender.getAvatar());

        try {
            // 3. 保存消息到数据库
            messageService.save(message); // 使用 IService 的 save 方法
            log.info("消息保存成功。消息ID: {}, 会话ID: {}, 发送者: {}, 接收者: {}",
                    message.getId(), message.getConversationId(), senderId, receiverId);

            // 4. 更新会话的最后消息时间
            conversationService.updateLastMessageAt(conversation.getId(), message.getCreatedTime());
            log.info("会话ID: {} 的最后消息时间已更新。", conversation.getId());

            // 5. 将消息发送给接收者
            messagingTemplate.convertAndSendToUser(
                    receiverId.toString(),
                    "/queue/messages", // 发送到用户的私有队列
                    message
            );
            log.info("消息已发送给接收者 {}，内容: {}", receiverId, message.getContent());

            // TODO: 可选：发回给发送者确认消息已成功处理 (比如发送一个状态消息到发送者的 /user/queue/ack)

        } catch (Exception e) {
            log.error("发送消息失败。SenderId: {}, ReceiverId: {}, 错误: {}",
                    senderId, receiverId, e.getMessage(), e);
            // 考虑发送一个错误消息给发送方
        }
    }

    /**
     * 处理用户进入聊天室的通知 (可选)
     * 客户端发送到 /app/chat.addUser
     *
     * @param message 消息体，通常只包含 senderId 和 type=JOIN
     * @param principal 当前认证用户的 Principal 对象
     */
    @MessageMapping("/chat.addUser")
    @ApiOperation("用户进入聊天室通知")
    public void addUser(@Payload Message message, Principal principal) {
        if (principal == null || principal.getName() == null) {
            log.warn("未认证用户（Principal中无ID）尝试加入聊天室！");
            return;
        }
        Long userId = Long.valueOf(principal.getName());

        message.setSenderId(userId);
        message.setType(Message.MessageType.JOIN);
        message.setCreatedTime(LocalDateTime.now());
        message.setStatus(Message.MessageStatus.SENT); // 假设加入也标记为 SENT 状态

        log.info("用户 {} 已上线/进入聊天室。", userId);

        // TODO: 根据业务需求进行处理，例如广播用户上线消息给所有相关用户
    }

    /**
     * 标记消息为已读
     * @param messagePayload 包含 messageId 和可能的 readerId
     * @param principal 当前认证用户的 Principal 对象
     */
    @MessageMapping("/chat.markRead")
    @ApiOperation("标记消息为已读")
    public void markMessageAsRead(@Payload Map<String, Object> messagePayload, Principal principal) {
        if (principal == null || principal.getName() == null) {
            log.warn("未认证用户（Principal中无ID）尝试标记消息为已读。");
            return;
        }
        Long readerId = Long.valueOf(principal.getName());

        // 从 Map 中安全地获取 Long 类型 ID
        Long messageId = null;
        Object msgIdObj = messagePayload.get("messageId");
        if (msgIdObj instanceof Number) { // 如果是数字类型（Long, Integer等）
            messageId = ((Number) msgIdObj).longValue();
        } else if (msgIdObj != null) { // 尝试从字符串转换
            try {
                messageId = Long.valueOf(msgIdObj.toString());
            } catch (NumberFormatException e) {
                log.warn("客户端发送的已读消息ID格式不正确。ReaderId: {}, messageIdRaw: {}", readerId, msgIdObj);
                return;
            }
        }

        if (messageId == null) {
            log.warn("客户端发送的已读消息ID为空。ReaderId: {}", readerId);
            return;
        }

        boolean success = messageService.markMessageAsRead(messageId, readerId);
        if (success) {
            log.info("用户 {} 标记消息 {} 为已读。", readerId, messageId);
            // 可选：通知发送者此消息已被读取
        } else {
            log.warn("用户 {} 标记消息 {} 为已读失败，可能原因：消息不存在、非接收者、或已是已读状态。", readerId, messageId);
        }
    }

    @GetMapping("/user/chat/conversations")
    @ApiOperation("获取用户会话列表")
    public Result<List<Conversation>> getConversations() {
        // REST API 继续从 BaseContext 获取用户ID，因为它发生在 HTTP 请求链路中
        Long userId = BaseContext.getCurrentId();

        if (userId == null) {
            log.warn("未认证用户（BaseContext中无ID）尝试获取会话列表。");
            return Result.error( "认证失败，请重新登录。"); // 明确返回 401 状态码
        }
        List<Conversation> conversations = conversationService.getConversationsByUserId(userId);
        return Result.success(conversations);
    }

    // REST API 接口
    @GetMapping("/user/chat/messages/{conversationId}")
    @ApiOperation("获取指定会话的历史消息")
    public Result<List<Message>> getChatHistory(@PathVariable Long conversationId,
                                                @RequestParam(defaultValue = "0") int page,
                                                @RequestParam(defaultValue = "20") int size) {
        // REST API 继续从 BaseContext 获取用户ID
        Long userId = BaseContext.getCurrentId();

        if (userId == null) {
            log.warn("未认证用户（BaseContext中无ID）尝试获取会话 {} 的历史消息。", conversationId);
            return Result.error( "认证失败，请重新登录。"); // 明确返回 401 状态码
        }

        // 验证用户是否是该会话的参与者
        if (!conversationService.isUserInConversation(userId, conversationId)) {
            log.warn("用户 {} 尝试访问无权限的会话 {}。", userId, conversationId);
            return Result.error("无权访问该会话。"); // 403 Forbidden
        }
        List<Message> messages = messageService.
                getConversationHistory(conversationId, page, size);
        return Result.success(messages);
    }


    @GetMapping("/user/chat/conversation/find")
    @ApiOperation("根据对方用户ID查找会话")
    public Result<Conversation> findConversationByPartnerId(@RequestParam Long partnerId) {
        // 1. 获取当前登录用户的ID
        Long currentUserId = BaseContext.getCurrentId();
        if (currentUserId == null) {
            return Result.error("认证失败");
        }

        // 2. 规范化用户ID对，与创建逻辑保持一致
        Long user1Id = Math.min(currentUserId, partnerId);
        Long user2Id = Math.max(currentUserId, partnerId);

        // 3. 调用 Service 层查找会话
        Conversation conversation = conversationService.findOrCreateConversation(user1Id,user2Id);

        // 4. 根据查找结果返回
        if (conversation != null) {
            // 如果找到，返回会话信息，HTTP 状态码 200
            return Result.success(conversation);
        } else {
            // 如果未找到，可以返回成功但data为null，前端会理解为新会话
            return Result.success(null);
        }
    }
}